package net.linku.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.linku.annotation.ChangeRecordEnums;
import net.linku.annotation.ChangeRecordLog;
import net.linku.annotation.change.service.IChangeService;
import net.linku.converter.PrivilegeMapperConverter;
import net.linku.domain.LAPrivilege;
import net.linku.enums.ErrorMessageEnums;
import net.linku.exception.LinkUException;
import net.linku.model.req.login.UserRequestParams;
import net.linku.model.req.privilege.AdminPrivilegeQuery;
import net.linku.model.req.privilege.AdminPrivilegeReq;
import net.linku.model.req.privilege.AdminStatusChangeReq;
import net.linku.model.resp.login.LAPrivilegeVO;
import net.linku.repository.LAPrivilegeRepository;
import net.linku.service.LAPrivilegeService;
import net.linku.service.LARoleService;
import net.linku.utils.TenantContext;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.util.List;

@Service
@Slf4j
@RequiredArgsConstructor
public class LAPrivilegeServiceImpl implements IChangeService<LAPrivilege>, LAPrivilegeService {

    private final LAPrivilegeRepository privilegeRepository;
    private final TransactionTemplate transactionTemplate;
    private final LARoleService laRoleService;
    private final MessageSource messageSource;

    /**
     * 根据用户请求参数获取权限数据
     *
     * @param userRequestParams 用户请求参数，包含租户ID和用户ID。
     * @return 符合条件的 LAPrivilege 列表。
     */
    @Override
    public List<LAPrivilege> getPrivilegesByAccountId(UserRequestParams userRequestParams) {
        List<LAPrivilege> privileges;

        // 判断用户是否是超级管理员
        if (laRoleService.isSuperAdmin(userRequestParams)) {
            // 如果是超级管理员，获取所有菜单
            privileges = privilegeRepository.list();
        } else {
            // 否则，根据用户ID和租户ID查询菜单
            privileges = privilegeRepository.queryPrivilegeByUserId(userRequestParams);
        }

        return privileges;
    }

    /**
     * 分页查询权限列表
     *
     * @param query 分页查询条件，包含当前页、页码和每页大小等信息。
     * @return 返回分页后的 LAPrivilegeVO 列表。
     */
    @Override
    public Page<LAPrivilegeVO> pagePrivilege(AdminPrivilegeQuery query) {
        // 执行分页查询
        Page<LAPrivilege> laPrivilegePage = privilegeRepository.pagePrivilege(query);

        // 将分页结果转换为 LAPrivilegeVO 对象
        return PrivilegeMapperConverter.INSTANCE.covertToPrivilege(laPrivilegePage);
    }

    /**
     * 添加权限并更新缓存
     *
     * @param privilegeReq 权限信息
     * @return 是否添加成功
     */
    @Override
    @ChangeRecordLog(serviceclass = LAPrivilegeServiceImpl.class,
            businessType = ChangeRecordEnums.TYPE.ADMIN_PRIVILEGE,
            action = ChangeRecordEnums.ACTION.INSERT,
            param = "#privilegeReq.id",
            changeType = ChangeRecordEnums.CHANGE_TYPE.INSERT,
            desc = "新建权限数据"
    )
    public Boolean addPrivilege(AdminPrivilegeReq privilegeReq) {
        // 打印日志，查看失效缓存时使用的键
        return privilegeInfoSaveOrUpdate(privilegeReq);
    }

    /**
     * 更新权限并刷新缓存
     *
     * @param privilegeReq 权限信息
     * @return 是否更新成功
     */
    @Override
    @ChangeRecordLog(serviceclass = LAPrivilegeServiceImpl.class,
            businessType = ChangeRecordEnums.TYPE.ADMIN_PRIVILEGE,
            action = ChangeRecordEnums.ACTION.MODIFY,
            param = "#privilegeReq.id",
            changeType = ChangeRecordEnums.CHANGE_TYPE.MODIFY,
            desc = "修改权限数据"
    )
    public Boolean updatePrivilege(AdminPrivilegeReq privilegeReq) {
        // 检查ID是否为空
        Assert.notNull(privilegeReq.getId(), "权限ID不能为空");
        // 调用 privilegeInfoSaveOrUpdate 方法进行保存或更新
        return privilegeInfoSaveOrUpdate(privilegeReq);
    }

    /**
     * 删除权限
     *
     * @param statusChangeReq 权限ID列表，表示需要删除的权限。
     * @return 返回是否删除成功的布尔值。
     */
    @Override
    public Boolean deletePrivilege(AdminStatusChangeReq statusChangeReq) {
        List<Long> ids = statusChangeReq.getIds();
        // 校验并查询权限信息
        getValidatedPrivilegeByIds(ids);
        // 执行删除操作
        return privilegeRepository.removeByIds(ids);
    }

    /**
     * 根据权限ID列表校验并查询权限信息
     *
     * @param ids 权限ID列表
     * @throws LinkUException 如果权限ID列表为空或未找到权限
     */
    private void getValidatedPrivilegeByIds(List<Long> ids) {
        // 根据ID列表查询权限信息
        List<LAPrivilege> privileges = privilegeRepository.listByIds(ids);

        // 如果未找到权限信息，抛出异常
        if (CollectionUtils.isEmpty(privileges)) {
            log.error("未找到权限信息，id列表: {}", ids);
            throw new LinkUException(ErrorMessageEnums.PRIVILEGE_INFO_NOT_EXISTS.getErrorCode(),
                    messageSource.getMessage(ErrorMessageEnums.PRIVILEGE_INFO_NOT_EXISTS.getErrorMsg(), null, LocaleContextHolder.getLocale()));
        }
    }

    /**
     * 保存或更新权限信息
     *
     * @param privilegeReq 新增/更新权限的请求对象
     * @return 如果操作成功则返回true，否则返回false
     */
    public Boolean privilegeInfoSaveOrUpdate(AdminPrivilegeReq privilegeReq) {
        // 将请求对象转换为LAPrivilege实体
        LAPrivilege laPrivilege = PrivilegeMapperConverter.INSTANCE.covertReqToPrivilege(privilegeReq);
        Long tenantId = Long.valueOf(TenantContext.getTenantId()); // 从上下文获取租户ID
        laPrivilege.setTenantId(tenantId);

        return transactionTemplate.execute(status -> {
            try {
                if (laPrivilege.getId() != null) {
                    LAPrivilege existingPrivilege = privilegeRepository.getById(laPrivilege.getId());
                    if (existingPrivilege != null) {
                        laPrivilege.setObjectVersionNumber(existingPrivilege.getObjectVersionNumber());
                        privilegeRepository.updateById(laPrivilege);
                        return true;
                    }
                }
                privilegeRepository.save(laPrivilege);
                privilegeReq.setId(laPrivilege.getId());
                return true;
            } catch (OptimisticLockingFailureException e) {
                status.setRollbackOnly();
                return false;
            } catch (Exception e) {
                status.setRollbackOnly();
                return false;
            }
        });
    }

    @Override
    public LAPrivilege queryDetail(Serializable id) {
        return privilegeRepository.getById(id);
    }
}
